﻿using System;
using System.Text;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json;
using Qs.App;
using Qs.App.Wx;
using Qs.Comm;
using Qs.Comm.Extensions;
using Qs.Comm.Model;
using Qs.Repository.Wx;
using WxPayAPI;

namespace Qs.WebApi.Controllers;

/// <summary>
/// 微信退款回调
/// </summary>
[Route("api/[controller]/[action]")]
[ApiController]

public class WeChatRefundNotify : ControllerBase
{
    /// <summary>
    /// 支付配置
    /// </summary>
    private readonly AppStoreSettingPay _appSettingPay;

    /// <summary>
    /// 退款
    /// </summary>
    private readonly AppOrderRefundSku _appOrderRefundSku;

    /// <summary>
    ///  构造函数
    /// </summary>
    /// <param name="appSettingPay">支付配置</param>
    /// <param name="appOrderRefundSku">退款</param>
    public WeChatRefundNotify(
        AppStoreSettingPay appSettingPay,
        AppOrderRefundSku appOrderRefundSku)
    {
        _appSettingPay = appSettingPay;
        _appOrderRefundSku = appOrderRefundSku;
    }

    /// <summary>
    /// 退款通知
    /// </summary>
    /// <returns>ActionResult</returns>
    /// <param name="storeId">storeId</param>
    [HttpPost("{storeId}")]
    [AllowAnonymous]
    public ActionResult RefundNotify(string storeId)
    {
        try
        {
            var setting = _appSettingPay.GetWxPayDetail(storeId);
            var stream = HttpContext.Request.Body;
            if (HttpContext.Request.ContentLength != null)
            {
                var buffer = new byte[HttpContext.Request.ContentLength.Value];
                var read = stream.Read(buffer, 0, buffer.Length);
                if (read != buffer.Length)
                {
                    throw new CustomException(404, "读取微信通知数据失败");
                }
                var content = Encoding.UTF8.GetString(buffer);

                //< xml >
                //< return_code > SUCCESS </ return_code >
                //< appid >< ! [CDATA[wx8888888888888888]] ></ appid >
                //< mch_id >< ! [CDATA[1900000109]] ></ mch_id >
                //< nonce_str >< ! [CDATA[5K8264ILTKCH16CQ2502SI8ZNMTM67VS]] ></ nonce_str >
                //< req_info >< ! [CDATA[T87GAHG17TGAHG1TGHAHAHA1Y1CIOA9UGJH1GAHV871HAGAGQYQQPOOJMXNBCXBVNMNMAJAA]] ></ req_info >
                //< return_msg >< ! [CDATA[90]] ></ return_msg >
                //</ xml >
                xLog.Add(new ModelLog
                {
                    Title = "退款通知1",
                    Href = "WeChatPayNotify.RefundNotify",
                    CreateName = "",
                    TypeName = "操作日志",
                    ApiInContent = content,
                    ApiOutContent = ""
                });

                var notifyData = new WxNotify().GetRefundNotifyData(content, setting);
                //检查支付结果中transaction_id是否存在
                if (!notifyData.IsSet("transaction_id"))
                {
                    throw new Exception($"支付结果中微信订单号不存在");
                }
                if (!notifyData.IsSet("refund_status"))
                {
                    throw new Exception("退款状态不存在");
                }

                var refundNotifyModel = ToRefundNotifyModel(notifyData);

                xLog.Add(new ModelLog
                {
                    Title = "退款通知2",
                    Href = "WeChatPayNotify.RefundNotify",
                    CreateName = "",
                    TypeName = "操作日志",
                    ApiInContent = JsonConvert.SerializeObject(refundNotifyModel),
                    ApiOutContent = ""
                });

                _appOrderRefundSku.RefundNotify(refundNotifyModel);
            }
            var xml = PayNotifyXml();
            return Content(xml, "text/xml");
        }
        catch (Exception ex)
        {
            var xml = PayNotifyXml("FAIL", ex.Message);
            WxLog.Error(this.GetType().ToString(), "error:" + xml);
            return Content(xml, "text/xml");
        }

        WxPayRefundNotifyModel ToRefundNotifyModel(WxPayData notifyData)
        {
            if (notifyData == null) throw new ArgumentNullException(nameof(notifyData));

            return new WxPayRefundNotifyModel
            {
                TransactionId = xConv.ToString(notifyData.GetValue("transaction_id")),
                OutTradeNo = xConv.ToString(notifyData.GetValue("out_trade_no")),
                RefundId = xConv.ToString(notifyData.GetValue("refund_id")),
                OutRefundNo = xConv.ToString(notifyData.GetValue("out_refund_no")),
                TotalFee = xConv.ToInt(notifyData.GetValue("total_fee")),
                SettlementTotalFee = xConv.ToNullableInt(notifyData.GetValue("settlement_total_fee")),
                RefundFee = xConv.ToInt(notifyData.GetValue("refund_fee")),
                SettlementRefundFee = xConv.ToInt(notifyData.GetValue("settlement_refund_fee")),
                RefundStatus = xConv.ToString(notifyData.GetValue("refund_status")),
                SuccessTime = xConv.ToDateTime(notifyData.GetValue("success_time")),
                RefundRecvAccount = xConv.ToString(notifyData.GetValue("refund_recv_account")),
                RefundAccount = xConv.ToString(notifyData.GetValue("refund_account")),
                RefundRequestSource = xConv.ToString(notifyData.GetValue("refund_request_source")),
                CashRefundFee = xConv.ToInt(notifyData.GetValue("cash_refund_fee"))
            };
        }
    }

    /// <summary>
    /// 收到财付通消息后返回的回调通知
    /// </summary>
    /// <param name="returnCode"></param>
    /// <param name="returnMsg"></param>
    /// <returns></returns>
    private static string PayNotifyXml(string returnCode = "SUCCESS", string returnMsg = "OK")
    {
        return
            $"<xml><return_code><![CDATA[{returnCode}]]></return_code><return_msg><![CDATA[{returnMsg}]]></return_msg></xml>";

    }
}